home *** CD-ROM | disk | FTP | other *** search
- Subject: v09i044: MicroEMACS, version 3.8b, Part12/14
- Newsgroups: mod.sources
- Approved: rs@mirror.TMC.COM
-
- Submitted by: ihnp4!itivax!duncan!lawrence (Daniel Lawrence)
- Mod.sources: Volume 9, Issue 44
- Archive-name: uemacs3.8b/Part12
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line,
- # then unpack it by saving it in a file and typing "sh file".
- # If this archive is complete, you will see the message:
- # "End of archive 12 (of 14)."
- # Contents: search.c
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo shar: Extracting \"search.c\" \(30773 characters\)
- if test -f search.c ; then
- echo shar: Will not over-write existing file \"search.c\"
- else
- sed "s/^X//" >search.c <<'END_OF_search.c'
- X/*
- X * The functions in this file implement commands that search in the forward
- X * and backward directions. There are no special characters in the search
- X * strings. Probably should have a regular expression search, or something
- X * like that.
- X *
- X * Aug. 1986 John M. Gamble:
- X * Made forward and reverse search use the same scan routine.
- X *
- X * Added a limited number of regular expressions - 'any',
- X * 'character class', 'closure', 'beginning of line', and
- X * 'end of line'.
- X *
- X * Replacement metacharacters will have to wait for a re-write of
- X * the replaces function, and a new variation of ldelete().
- X *
- X * For those curious as to my references, i made use of
- X * Kernighan & Plauger's "Software Tools."
- X * I deliberately did not look at any published grep or editor
- X * source (aside from this one) for inspiration. I did make use of
- X * Allen Hollub's bitmap routines as published in Doctor Dobb's Journal,
- X * June, 1985 and modified them for the limited needs of character class
- X * matching. Any inefficiences, bugs, stupid coding examples, etc.,
- X * are therefore my own responsibility.
- X */
- X
- X#include <stdio.h>
- X#include "estruct.h"
- X#include "edef.h"
- X#include "esearch.h"
- X
- X/*
- X * Reversed pattern array.
- X */
- Xchar tap[NPAT];
- X
- X#if MAGIC
- X/*
- X * The variable magical determines if there are actual
- X * metacharacters in the string - if not, then we don't
- X * have to use the slower MAGIC mode search functions.
- X *
- X * The variable mclen holds the length of the matched
- X * string - used by the replace functions.
- X *
- X * The arrays mcpat and tapcm hold the MC and reversed
- X * MC search structures.
- X */
- Xshort int magical = FALSE;
- Xint mclen = 0;
- XMC mcpat[NPAT];
- XMC tapcm[NPAT];
- X#endif
- X
- X/*
- X * forwsearch -- Search forward. Get a search string from the user, and
- X * search, beginning at ".", for the string. If found, reset the "."
- X * to be just after the match string, and (perhaps) repaint the display.
- X */
- X
- Xforwsearch(f, n)
- X{
- X register int status = TRUE;
- X
- X /* Resolve the repeat count.
- X */
- X if (n == 0)
- X n = 1;
- X
- X /* If n is negative, search backwards.
- X * Otherwise proceed by asking for the search string.
- X */
- X if (n < 0)
- X status = backsearch(f, -n);
- X
- X /* Ask the user for the text of a pattern. If the
- X * response is TRUE (responses other than FALSE are
- X * possible), search for the pattern.
- X */
- X else if ((status = readpattern("Search", &pat[0], TRUE)) == TRUE)
- X {
- X do
- X {
- X#if MAGIC
- X if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
- X status = mcscanner(&mcpat[0], FORWARD, PTEND);
- X else
- X#endif
- X status = scanner(&pat[0], FORWARD, PTEND);
- X } while ((--n > 0) && status);
- X
- X /* ...and complain if not there.
- X */
- X if (status == FALSE)
- X mlwrite("Not found");
- X }
- X return(status);
- X}
- X
- X/*
- X * forwhunt -- Search forward for a previously acquired search string,
- X * beginning at ".". If found, reset the "." to be just after
- X * the match string, and (perhaps) repaint the display.
- X */
- X
- Xforwhunt(f, n)
- X{
- X register int status = TRUE;
- X
- X /* Resolve the repeat count.
- X */
- X if (n == 0)
- X n = 1;
- X else if (n < 0) /* search backwards */
- X return(backhunt(f, -n));
- X
- X /* Make sure a pattern exists, or that we didn't switch
- X * into MAGIC mode until after we entered the pattern.
- X */
- X if (pat[0] == '\0')
- X {
- X mlwrite("No pattern set");
- X return FALSE;
- X }
- X#if MAGIC
- X if ((curwp->w_bufp->b_mode & MDMAGIC) != 0 &&
- X mcpat[0].mc_type == MCNIL)
- X {
- X if (!mcstr())
- X return FALSE;
- X }
- X#endif
- X
- X /* Search for the pattern...
- X */
- X do
- X {
- X#if MAGIC
- X if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
- X status = mcscanner(&mcpat[0], FORWARD, PTEND);
- X else
- X#endif
- X status = scanner(&pat[0], FORWARD, PTEND);
- X } while ((--n > 0) && status);
- X
- X /* ...and complain if not there.
- X */
- X if (status == FALSE)
- X mlwrite("Not found");
- X
- X return(status);
- X}
- X
- X/*
- X * backsearch -- Reverse search. Get a search string from the user, and
- X * search, starting at "." and proceeding toward the front of the buffer.
- X * If found "." is left pointing at the first character of the pattern
- X * (the last character that was matched).
- X */
- Xbacksearch(f, n)
- X{
- X register int status = TRUE;
- X
- X /* Resolve null and negative arguments.
- X */
- X if (n == 0)
- X n = 1;
- X
- X /* If n is negative, search forwards.
- X * Otherwise proceed by asking for the search string.
- X */
- X if (n < 0)
- X status = forwsearch(f, -n);
- X
- X /* Ask the user for the text of a pattern. If the
- X * response is TRUE (responses other than FALSE are
- X * possible), search for the pattern.
- X */
- X else if ((status = readpattern("Reverse search", &pat[0], TRUE)) == TRUE)
- X {
- X do
- X {
- X#if MAGIC
- X if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
- X status = mcscanner(&tapcm[0], REVERSE, PTBEG);
- X else
- X#endif
- X status = scanner(&tap[0], REVERSE, PTBEG);
- X } while ((--n > 0) && status);
- X
- X /* ...and complain if not there.
- X */
- X if (status == FALSE)
- X mlwrite("Not found");
- X }
- X return(status);
- X}
- X
- X/*
- X * backhunt -- Reverse search for a previously acquired search string,
- X * starting at "." and proceeding toward the front of the buffer.
- X * If found "." is left pointing at the first character of the pattern
- X * (the last character that was matched).
- X */
- Xbackhunt(f, n)
- X{
- X register int status = TRUE;
- X
- X /* Resolve null and negative arguments.
- X */
- X if (n == 0)
- X n = 1;
- X else if (n < 0)
- X return(forwhunt(f, -n));
- X
- X /* Make sure a pattern exists, or that we didn't switch
- X * into MAGIC mode until after we entered the pattern.
- X */
- X if (tap[0] == '\0')
- X {
- X mlwrite("No pattern set");
- X return FALSE;
- X }
- X#if MAGIC
- X if ((curwp->w_bufp->b_mode & MDMAGIC) != 0 &&
- X tapcm[0].mc_type == MCNIL)
- X {
- X if (!mcstr())
- X return FALSE;
- X }
- X#endif
- X
- X /* Go search for it...
- X */
- X do
- X {
- X#if MAGIC
- X if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
- X status = mcscanner(&tapcm[0], REVERSE, PTBEG);
- X else
- X#endif
- X status = scanner(&tap[0], REVERSE, PTBEG);
- X } while ((--n > 0) && status);
- X
- X /* ...and complain if not there.
- X */
- X if (status == FALSE)
- X mlwrite("Not found");
- X
- X return(status);
- X}
- X
- X#if MAGIC
- X/*
- X * mcscanner -- Search for a meta-pattern in either direction.
- X */
- Xint mcscanner(mcpatrn, direct, beg_or_end)
- XMC *mcpatrn; /* pointer into pattern */
- Xint direct; /* which way to go.*/
- Xint beg_or_end; /* put point at beginning or end of pattern.*/
- X{
- X register LINE *lastline; /* last line position during scan */
- X register int lastoff; /* position within last line */
- X LINE *curline; /* current line during scan */
- X int curoff; /* position within current line */
- X int c; /* (dummy) char at current position */
- X
- X /* If we are going in reverse, then the 'end' is actually
- X * the beginning of the pattern. Toggle it.
- X */
- X beg_or_end ^= direct;
- X
- X /* Setup local scan pointers to global ".".
- X */
- X curline = curwp->w_dotp;
- X curoff = curwp->w_doto;
- X
- X /* Scan each character until we hit the head link record.
- X */
- X while (!boundry(curline, curoff, direct))
- X {
- X /* Save the current position in case we need to
- X * restore it on a match, and initialize mclen to
- X * zero in case we are doing a search for replacement.
- X */
- X lastline = curline;
- X lastoff = curoff;
- X mclen = 0;
- X
- X if (amatch(mcpatrn, direct, &curline, &curoff))
- X {
- X /* A SUCCESSFULL MATCH!!!
- X * reset the global "." pointers.
- X */
- X if (beg_or_end == PTEND) /* at end of string */
- X {
- X curwp->w_dotp = curline;
- X curwp->w_doto = curoff;
- X }
- X else /* at beginning of string */
- X {
- X curwp->w_dotp = lastline;
- X curwp->w_doto = lastoff;
- X }
- X
- X curwp->w_flag |= WFMOVE; /* flag that we have moved */
- X return TRUE;
- X }
- X
- X /* Advance the cursor.
- X */
- X c = nextch(&curline, &curoff, direct);
- X }
- X
- X return FALSE; /* We could not find a match.*/
- X}
- X
- X/*
- X * amatch -- Search for a meta-pattern in either direction. Based on the
- X * recursive routine amatch() (for "anchored match") in
- X * Kernighan & Plauger's "Software Tools".
- X */
- Xstatic int amatch(mcptr, direct, pcwline, pcwoff)
- Xregister MC *mcptr; /* string to scan for */
- Xint direct; /* which way to go.*/
- XLINE **pcwline; /* current line during scan */
- Xint *pcwoff; /* position within current line */
- X{
- X register int c; /* character at current position */
- X LINE *curline; /* current line during scan */
- X int curoff; /* position within current line */
- X int nchars;
- X
- X /* Set up local scan pointers to ".", and get
- X * the current character. Then loop around
- X * the pattern pointer until success or failure.
- X */
- X curline = *pcwline;
- X curoff = *pcwoff;
- X
- X /* The beginning-of-line and end-of-line metacharacters
- X * do not compare against characters, they compare
- X * against positions.
- X * BOL is guaranteed to be at the start of the pattern
- X * for forward searches, and at the end of the pattern
- X * for reverse searches. The reverse is true for EOL.
- X * So, for a start, we check for them on entry.
- X */
- X if (mcptr->mc_type == BOL)
- X {
- X if (curoff != 0)
- X return FALSE;
- X mcptr++;
- X }
- X
- X if (mcptr->mc_type == EOL)
- X {
- X if (curoff != llength(curline))
- X return FALSE;
- X mcptr++;
- X }
- X
- X while (mcptr->mc_type != MCNIL)
- X {
- X c = nextch(&curline, &curoff, direct);
- X
- X if (mcptr->mc_type & CLOSURE)
- X {
- X /* Try to match as many characters as possible
- X * against the current meta-character. A
- X * newline never matches a closure.
- X */
- X nchars = 0;
- X while (c != '\n' && mceq(c, mcptr))
- X {
- X c = nextch(&curline, &curoff, direct);
- X nchars++;
- X }
- X
- X /* We are now at the character that made us
- X * fail. Try to match the rest of the pattern.
- X * Shrink the closure by one for each failure.
- X * Since closure matches *zero* or more occurences
- X * of a pattern, a match may start even if the
- X * previous loop matched no characters.
- X */
- X mcptr++;
- X
- X for (;;)
- X {
- X c = nextch(&curline, &curoff, direct ^ REVERSE);
- X
- X if (amatch(mcptr, direct, &curline, &curoff))
- X {
- X mclen += nchars;
- X goto success;
- X }
- X
- X if (nchars-- == 0)
- X return FALSE;
- X }
- X }
- X else /* Not closure.*/
- X {
- X /* The only way we'd get a BOL metacharacter
- X * at this point is at the end of the reversed pattern.
- X * The only way we'd get an EOL metacharacter
- X * here is at the end of a regular pattern.
- X * So if we match one or the other, and are at
- X * the appropriate position, we are guaranteed success
- X * (since the next pattern character has to be MCNIL).
- X * Before we report success, however, we back up by
- X * one character, so as to leave the cursor in the
- X * correct position. For example, a search for ")$"
- X * will leave the cursor at the end of the line, while
- X * a search for ")<NL>" will leave the cursor at the
- X * beginning of the next line. This follows the
- X * notion that the meta-character '$' (and likewise
- X * '^') match positions, not characters.
- X */
- X if (mcptr->mc_type == BOL)
- X if (curoff == llength(curline))
- X {
- X c = nextch(&curline, &curoff,
- X direct ^ REVERSE);
- X goto success;
- X }
- X else
- X return FALSE;
- X
- X if (mcptr->mc_type == EOL)
- X if (curoff == 0)
- X {
- X c = nextch(&curline, &curoff,
- X direct ^ REVERSE);
- X goto success;
- X }
- X else
- X return FALSE;
- X
- X /* Neither BOL nor EOL, so go through
- X * the meta-character equal function.
- X */
- X if (!mceq(c, mcptr))
- X return FALSE;
- X }
- X
- X /* Increment the length counter and
- X * advance the pattern pointer.
- X */
- X mclen++;
- X mcptr++;
- X } /* End of mcptr loop.*/
- X
- X /* A SUCCESSFULL MATCH!!!
- X * Reset the "." pointers.
- X */
- Xsuccess:
- X *pcwline = curline;
- X *pcwoff = curoff;
- X
- X return TRUE;
- X}
- X#endif
- X
- X/*
- X * scanner -- Search for a pattern in either direction.
- X */
- Xint scanner(patrn, direct, beg_or_end)
- Xchar *patrn; /* string to scan for */
- Xint direct; /* which way to go.*/
- Xint beg_or_end; /* put point at beginning or end of pattern.*/
- X{
- X register int c; /* character at current position */
- X register char *patptr; /* pointer into pattern */
- X register LINE *lastline; /* last line position during scan */
- X register int lastoff; /* position within last line */
- X LINE *curline; /* current line during scan */
- X int curoff; /* position within current line */
- X LINE *matchline; /* current line during matching */
- X int matchoff; /* position in matching line */
- X
- X /* If we are going in reverse, then the 'end' is actually
- X * the beginning of the pattern. Toggle it.
- X */
- X beg_or_end ^= direct;
- X
- X /* Setup local scan pointers to global ".".
- X */
- X curline = curwp->w_dotp;
- X curoff = curwp->w_doto;
- X
- X /* Scan each character until we hit the head link record.
- X */
- X while (!boundry(curline, curoff, direct))
- X {
- X /* Save the current position in case we need to
- X * restore it on a match.
- X */
- X lastline = curline;
- X lastoff = curoff;
- X
- X /* Get the character resolving newlines, and
- X * test it against first char in pattern.
- X */
- X c = nextch(&curline, &curoff, direct);
- X
- X if (eq(c, patrn[0])) /* if we find it..*/
- X {
- X /* Setup match pointers.
- X */
- X matchline = curline;
- X matchoff = curoff;
- X patptr = &patrn[0];
- X
- X /* Scan through the pattern for a match.
- X */
- X while (*++patptr != '\0')
- X {
- X c = nextch(&matchline, &matchoff, direct);
- X
- X if (!eq(c, *patptr))
- X goto fail;
- X }
- X
- X /* A SUCCESSFULL MATCH!!!
- X * reset the global "." pointers
- X */
- X if (beg_or_end == PTEND) /* at end of string */
- X {
- X curwp->w_dotp = matchline;
- X curwp->w_doto = matchoff;
- X }
- X else /* at beginning of string */
- X {
- X curwp->w_dotp = lastline;
- X curwp->w_doto = lastoff;
- X }
- X
- X curwp->w_flag |= WFMOVE; /* Flag that we have moved.*/
- X return TRUE;
- X
- X }
- Xfail:; /* continue to search */
- X }
- X
- X return FALSE; /* We could not find a match */
- X}
- X
- X/*
- X * eq -- Compare two characters. The "bc" comes from the buffer, "pc"
- X * from the pattern. If we are not in EXACT mode, fold out the case.
- X */
- Xint eq(bc, pc)
- Xregister int bc;
- Xregister int pc;
- X{
- X if ((curwp->w_bufp->b_mode & MDEXACT) == 0)
- X {
- X if (islower(bc))
- X bc ^= DIFCASE;
- X
- X if (islower(pc))
- X pc ^= DIFCASE;
- X }
- X
- X return (bc == pc);
- X}
- X
- X/*
- X * readpattern -- Read a pattern. Stash it in apat. If it is the
- X * search string, create the reverse pattern and the magic
- X * pattern, assuming we are in MAGIC mode (and defined that way).
- X * Apat is not updated if the user types in an empty line. If
- X * the user typed an empty line, and there is no old pattern, it is
- X * an error. Display the old pattern, in the style of Jeff Lomicka.
- X * There is some do-it-yourself control expansion. Change to using
- X * <META> to delimit the end-of-pattern to allow <NL>s in the search
- X * string.
- X */
- Xstatic int readpattern(prompt, apat, srch)
- Xchar *prompt;
- Xchar apat[];
- Xint srch;
- X{
- X int status;
- X char tpat[NPAT+20];
- X
- X strcpy(tpat, prompt); /* copy prompt to output string */
- X strcat(tpat, " ["); /* build new prompt string */
- X expandp(&apat[0], &tpat[strlen(tpat)], NPAT/2); /* add old pattern */
- X strcat(tpat, "]<META>: ");
- X
- X /* Read a pattern. Either we get one,
- X * or we just get the META charater, and use the previous pattern.
- X * Then, if it's the search string, make a reversed pattern.
- X * *Then*, make the meta-pattern, if we are defined that way.
- X */
- X if ((status = mlreplyt(tpat, tpat, NPAT, metac)) == TRUE)
- X {
- X strcpy(apat, tpat);
- X if (srch) /* If we are doing the search string.*/
- X {
- X /* Reverse string copy.
- X */
- X rvstrcpy(tap, apat);
- X#if MAGIC
- X /* Only make the meta-pattern if in magic mode,
- X * since the pattern in question might have an
- X * invalid meta combination.
- X */
- X if ((curwp->w_bufp->b_mode & MDMAGIC) == 0)
- X mcpat[0].mc_type = tapcm[0].mc_type = MCNIL;
- X else
- X status = mcstr();
- X#endif
- X }
- X }
- X else if (status == FALSE && apat[0] != 0) /* Old one */
- X status = TRUE;
- X
- X return(status);
- X}
- X
- X/*
- X * rvstrcpy -- Reverse string copy.
- X */
- Xrvstrcpy(rvstr, str)
- Xregister char *rvstr, *str;
- X{
- X register int i;
- X
- X str += (i = strlen(str));
- X
- X while (i-- > 0)
- X *rvstr++ = *--str;
- X
- X *rvstr = '\0';
- X}
- X
- X/*
- X * sreplace -- Search and replace.
- X */
- Xsreplace(f, n)
- Xint f; /* default flag */
- Xint n; /* # of repetitions wanted */
- X{
- X return(replaces(FALSE, f, n));
- X}
- X
- X/*
- X * qreplace -- search and replace with query.
- X */
- Xqreplace(f, n)
- Xint f; /* default flag */
- Xint n; /* # of repetitions wanted */
- X{
- X return(replaces(TRUE, f, n));
- X}
- X
- X/*
- X * replaces -- Search for a string and replace it with another
- X * string. Query might be enabled (according to kind).
- X */
- Xstatic int replaces(kind, f, n)
- Xint kind; /* Query enabled flag */
- Xint f; /* default flag */
- Xint n; /* # of repetitions wanted */
- X{
- X register int i; /* loop index */
- X register int status; /* success flag on pattern inputs */
- X register int slength,
- X rlength; /* length of search and replace strings */
- X register int numsub; /* number of substitutions */
- X register int nummatch; /* number of found matches */
- X int nlflag; /* last char of search string a <NL>? */
- X int nlrepl; /* was a replace done on the last line? */
- X char tmpc; /* temporary character */
- X char c; /* input char for query */
- X char tpat[NPAT]; /* temporary to hold search pattern */
- X LINE *origline; /* original "." position */
- X int origoff; /* and offset (for . query option) */
- X LINE *lastline; /* position of last replace and */
- X int lastoff; /* offset (for 'u' query option) */
- X
- X if (curbp->b_mode & MDVIEW) /* don't allow this command if */
- X return(rdonly()); /* we are in read only mode */
- X
- X /* Check for negative repetitions.
- X */
- X if (f && n < 0)
- X return(FALSE);
- X
- X /* Ask the user for the text of a pattern.
- X */
- X if ((status = readpattern(
- X (kind == FALSE ? "Replace" : "Query replace"), &pat[0], TRUE))
- X != TRUE)
- X return(status);
- X
- X /* Ask for the replacement string.
- X */
- X if ((status = readpattern("with", &rpat[0], FALSE)) == ABORT)
- X return(status);
- X
- X /* Find the lengths of the strings.
- X */
- X slength = strlen(&pat[0]);
- X rlength = strlen(&rpat[0]);
- X
- X /* Set up flags so we can make sure not to do a recursive
- X * replace on the last line.
- X */
- X nlflag = (pat[slength - 1] == '\n');
- X nlrepl = FALSE;
- X
- X if (kind)
- X {
- X /* Build query replace question string.
- X */
- X strcpy(tpat, "Replace '");
- X expandp(&pat[0], &tpat[strlen(tpat)], NPAT/3);
- X strcat(tpat, "' with '");
- X expandp(&rpat[0], &tpat[strlen(tpat)], NPAT/3);
- X strcat(tpat, "'? ");
- X
- X /* Initialize last replaced pointers.
- X */
- X lastline = NULL;
- X lastoff = 0;
- X }
- X
- X /* Save original . position, init the number of matches and
- X * substitutions, and scan through the file.
- X */
- X origline = curwp->w_dotp;
- X origoff = curwp->w_doto;
- X numsub = 0;
- X nummatch = 0;
- X
- X while ( (f == FALSE || n > nummatch) &&
- X (nlflag == FALSE || nlrepl == FALSE) )
- X {
- X /* Search for the pattern.
- X * If we search with a regular expression, also save
- X * the true length of matched string.
- X */
- X#if MAGIC
- X if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
- X {
- X if (!mcscanner(&mcpat[0], FORWARD, PTBEG))
- X break;
- X slength = mclen;
- X }
- X else
- X#endif
- X if (!scanner(&pat[0], FORWARD, PTBEG))
- X break; /* all done */
- X
- X ++nummatch; /* Increment # of matches */
- X
- X /* Check if we are on the last line.
- X */
- X nlrepl = (lforw(curwp->w_dotp) == curwp->w_bufp->b_linep);
- X
- X /* Check for query.
- X */
- X if (kind)
- X {
- X /* Get the query.
- X */
- Xpprompt: mlwrite(&tpat[0], &pat[0], &rpat[0]);
- Xqprompt:
- X update(); /* show the proposed place to change */
- X c = tgetc(); /* and input */
- X mlwrite(""); /* and clear it */
- X
- X /* And respond appropriately.
- X */
- X switch (c)
- X {
- X case 'y': /* yes, substitute */
- X case ' ':
- X break;
- X
- X case 'n': /* no, onword */
- X forwchar(FALSE, 1);
- X continue;
- X
- X case '!': /* yes/stop asking */
- X kind = FALSE;
- X break;
- X
- X case 'u': /* undo last and re-prompt */
- X
- X /* Restore old position.
- X */
- X if (lastline == NULL)
- X {
- X /* There is nothing to undo.
- X */
- X TTbeep();
- X goto qprompt;
- X }
- X curwp->w_dotp = lastline;
- X curwp->w_doto = lastoff;
- X lastline = NULL;
- X lastoff = 0;
- X
- X /* Delete the new string.
- X */
- X backchar(FALSE, rlength);
- X if (!ldelete(rlength, FALSE))
- X {
- X mlwrite("%%ERROR while deleting");
- X return(FALSE);
- X }
- X
- X /* And put in the old one.
- X */
- X for (i = 0; i < slength; i++)
- X {
- X tmpc = pat[i];
- X status = (tmpc == '\n'?
- X lnewline():
- X linsert(1, tmpc));
- X
- X /* Insertion error?
- X */
- X if (!status)
- X {
- X mlwrite("%%Out of memory while inserting");
- X return(FALSE);
- X }
- X }
- X
- X /* Record one less substitution,
- X * backup, and reprompt.
- X */
- X --numsub;
- X backchar(FALSE, slength);
- X goto pprompt;
- X
- X case '.': /* abort! and return */
- X /* restore old position */
- X curwp->w_dotp = origline;
- X curwp->w_doto = origoff;
- X curwp->w_flag |= WFMOVE;
- X
- X case BELL: /* abort! and stay */
- X mlwrite("Aborted!");
- X return(FALSE);
- X
- X default: /* bitch and beep */
- X TTbeep();
- X
- X case '?': /* help me */
- X mlwrite(
- X"(Y)es, (N)o, (!)Do rest, (U)ndo last, (^G)Abort, (.)Abort back, (?)Help: ");
- X goto qprompt;
- X
- X } /* end of switch */
- X } /* end of "if kind" */
- X
- X /*
- X * Delete the sucker.
- X */
- X if (!ldelete(slength, FALSE))
- X {
- X mlwrite("%%ERROR while deleteing");
- X return(FALSE);
- X }
- X
- X /* And insert its replacement.
- X */
- X for (i = 0; i < rlength; i++)
- X {
- X tmpc = rpat[i];
- X status = (tmpc == '\n'? lnewline(): linsert(1, tmpc));
- X
- X /* Insertion error?
- X */
- X if (!status)
- X {
- X mlwrite("%%Out of memory while inserting");
- X return(FALSE);
- X }
- X }
- X
- X /* Save where we are if we might undo this....
- X */
- X if (kind)
- X {
- X lastline = curwp->w_dotp;
- X lastoff = curwp->w_doto;
- X }
- X
- X numsub++; /* increment # of substitutions */
- X }
- X
- X /* And report the results.
- X */
- X mlwrite("%d substitutions", numsub);
- X return(TRUE);
- X}
- X
- X/*
- X * expandp -- Expand control key sequences for output.
- X */
- Xexpandp(srcstr, deststr, maxlength)
- Xchar *srcstr; /* string to expand */
- Xchar *deststr; /* destination of expanded string */
- Xint maxlength; /* maximum chars in destination */
- X{
- X char c; /* current char to translate */
- X
- X /* Scan through the string.
- X */
- X while ((c = *srcstr++) != 0)
- X {
- X if (c == '\n') /* it's a newline */
- X {
- X *deststr++ = '<';
- X *deststr++ = 'N';
- X *deststr++ = 'L';
- X *deststr++ = '>';
- X maxlength -= 4;
- X }
- X else if (c < 0x20 || c == 0x7f) /* control character */
- X {
- X *deststr++ = '^';
- X *deststr++ = c ^ 0x40;
- X maxlength -= 2;
- X }
- X else if (c == '%')
- X {
- X *deststr++ = '%';
- X *deststr++ = '%';
- X maxlength -= 2;
- X }
- X else /* any other character */
- X {
- X *deststr++ = c;
- X maxlength--;
- X }
- X
- X /* check for maxlength */
- X if (maxlength < 4)
- X {
- X *deststr++ = '$';
- X *deststr = '\0';
- X return(FALSE);
- X }
- X }
- X *deststr = '\0';
- X return(TRUE);
- X}
- X
- X/*
- X * boundry -- Return information depending on whether we may search no
- X * further. Beginning of file and end of file are the obvious
- X * cases, but we may want to add further optional boundry restrictions
- X * in future, a' la VMS EDT. At the moment, just return TRUE or
- X * FALSE depending on if a boundry is hit (ouch).
- X */
- Xint boundry(curline, curoff, dir)
- XLINE *curline;
- Xint curoff, dir;
- X{
- X register int border;
- X
- X if (dir == FORWARD)
- X {
- X border = (curoff == llength(curline)) &&
- X (lforw(curline) == curbp->b_linep);
- X }
- X else
- X {
- X border = (curoff == 0) &&
- X (lback(curline) == curbp->b_linep);
- X }
- X return (border);
- X}
- X
- X/*
- X * nextch -- retrieve the next/previous character in the buffer,
- X * and advance/retreat the point.
- X * The order in which this is done is significant, and depends
- X * upon the direction of the search. Forward searches look at
- X * the current character and move, reverse searches move and
- X * look at the character.
- X */
- Xstatic int nextch(pcurline, pcuroff, dir)
- XLINE **pcurline;
- Xint *pcuroff;
- Xint dir;
- X{
- X register LINE *curline;
- X register int curoff;
- X register int c;
- X
- X curline = *pcurline;
- X curoff = *pcuroff;
- X
- X if (dir == FORWARD)
- X {
- X if (curoff == llength(curline)) /* if at EOL */
- X {
- X curline = lforw(curline); /* skip to next line */
- X curoff = 0;
- X c = '\n'; /* and return a <NL> */
- X }
- X else
- X c = lgetc(curline, curoff++); /* get the char */
- X }
- X else /* Reverse.*/
- X {
- X if (curoff == 0)
- X {
- X curline = lback(curline);
- X curoff = llength(curline);
- X c = '\n';
- X }
- X else
- X c = lgetc(curline, --curoff);
- X
- X }
- X *pcurline = curline;
- X *pcuroff = curoff;
- X
- X return (c);
- X}
- X
- X#if MAGIC
- X/*
- X * mcstr -- Set up the 'magic' array. The closure symbol is taken as
- X * a literal character when (1) it is the first character in the
- X * pattern, and (2) when preceded by a symbol that does not allow
- X * closure, such as a newline, beginning of line symbol, or another
- X * closure symbol.
- X *
- X * Coding comment (jmg): yes, i know i have gotos that are, strictly
- X * speaking, unnecessary. But right now we are so cramped for
- X * code space that i will grab what i can in order to remain
- X * within the 64K limit. C compilers actually do very little
- X * in the way of optimizing - they expect you to do that.
- X */
- Xstatic int mcstr()
- X{
- X MC *mcptr, *rtpcm;
- X char *patptr;
- X int mj;
- X int pchr;
- X int status = TRUE;
- X int does_closure = FALSE;
- X
- X /* If we had metacharacters in the MC array previously,
- X * free up any bitmaps that may have been allocated.
- X */
- X if (magical)
- X freebits();
- X
- X magical = FALSE;
- X mj = 0;
- X mcptr = &mcpat[0];
- X patptr = &pat[0];
- X
- X while ((pchr = *patptr) && status)
- X {
- X switch (pchr)
- X {
- X case MC_CCL:
- X status = cclmake(&patptr, mcptr);
- X magical = TRUE;
- X does_closure = TRUE;
- X break;
- X case MC_BOL:
- X if (mj != 0)
- X goto litcase;
- X
- X mcptr->mc_type = BOL;
- X magical = TRUE;
- X does_closure = FALSE;
- X break;
- X case MC_EOL:
- X if (*(patptr + 1) != '\0')
- X goto litcase;
- X
- X mcptr->mc_type = EOL;
- X magical = TRUE;
- X does_closure = FALSE;
- X break;
- X case MC_ANY:
- X mcptr->mc_type = ANY;
- X magical = TRUE;
- X does_closure = TRUE;
- X break;
- X case MC_CLOSURE:
- X /* Does the closure symbol mean closure here?
- X * If so, back up to the previous element
- X * and indicate it is enclosed.
- X */
- X if (!does_closure)
- X goto litcase;
- X mj--;
- X mcptr--;
- X mcptr->mc_type |= CLOSURE;
- X magical = TRUE;
- X does_closure = FALSE;
- X break;
- X
- X /* Note: no break between MC_ESC case and the default.
- X */
- X case MC_ESC:
- X if (*(patptr + 1) != '\0')
- X {
- X pchr = *++patptr;
- X magical = TRUE;
- X }
- X default:
- Xlitcase: mcptr->mc_type = LITCHAR;
- X mcptr->u.lchar = pchr;
- X does_closure = (pchr != '\n');
- X break;
- X } /* End of switch.*/
- X mcptr++;
- X patptr++;
- X mj++;
- X } /* End of while.*/
- X
- X /* Close off the meta-string.
- X */
- X mcptr->mc_type = MCNIL;
- X
- X /* Set up the reverse array, if the status is good. Please note the
- X * structure assignment - your compiler may not like that.
- X * If the status is not good, nil out the meta-pattern.
- X * The only way the status would be bad is from the cclmake()
- X * routine, and the bitmap for that member is guarenteed to be
- X * freed. So we stomp a MCNIL value there, call freebits() to
- X * free any other bitmaps, and set the zeroth array to MCNIL.
- X */
- X if (status)
- X {
- X rtpcm = &tapcm[0];
- X while (--mj >= 0)
- X {
- X#if LATTICE
- X movmem(--mcptr, rtpcm++, sizeof (MC));
- X#endif
- X
- X#if MWC86 | AZTEC | MSC | VMS | USG | BSD | V7
- X *rtpcm++ = *--mcptr;
- X#endif
- X }
- X rtpcm->mc_type = MCNIL;
- X }
- X else
- X {
- X (--mcptr)->mc_type = MCNIL;
- X freebits();
- X mcpat[0].mc_type = tapcm[0].mc_type = MCNIL;
- X }
- X
- X return(status);
- X}
- X
- X/*
- X * mceq -- meta-character equality with a character. In Kernighan & Plauger's
- X * Software Tools, this is the function omatch(), but i felt there
- X * were too many functions with the 'match' name already.
- X */
- Xstatic int mceq(bc, mt)
- Xint bc;
- XMC *mt;
- X{
- X register int result;
- X
- X switch (mt->mc_type & MASKCL)
- X {
- X case LITCHAR:
- X result = eq(bc, mt->u.lchar);
- X break;
- X
- X case ANY:
- X result = (bc != '\n');
- X break;
- X
- X case CCL:
- X if (!(result = biteq(bc, mt->u.cclmap)))
- X {
- X if ((curwp->w_bufp->b_mode & MDEXACT) == 0 &&
- X (isletter(bc)))
- X {
- X result = biteq(CHCASE(bc), mt->u.cclmap);
- X }
- X }
- X break;
- X
- X case NCCL:
- X result = !biteq(bc, mt->u.cclmap);
- X
- X if ((curwp->w_bufp->b_mode & MDEXACT) == 0 &&
- X (isletter(bc)))
- X {
- X result &= !biteq(CHCASE(bc), mt->u.cclmap);
- X }
- X break;
- X
- X default:
- X mlwrite("mceq: what is %d?", mt->mc_type);
- X result = FALSE;
- X break;
- X
- X } /* End of switch.*/
- X
- X return (result);
- X}
- X
- X/*
- X * cclmake -- create the bitmap for the character class.
- X * ppatptr is left pointing to the end-of-character-class character,
- X * so that a loop may automatically increment with safety.
- X */
- Xstatic int cclmake(ppatptr, mcptr)
- Xchar **ppatptr;
- XMC *mcptr;
- X{
- X BITMAP clearbits();
- X BITMAP bmap;
- X register char *patptr;
- X register int pchr, ochr;
- X
- X if ((bmap = clearbits()) == NULL)
- X {
- X mlwrite("%%Out of memory");
- X return FALSE;
- X }
- X
- X mcptr->u.cclmap = bmap;
- X patptr = *ppatptr;
- X
- X /*
- X * Test the initial character(s) in ccl for
- X * special cases - negate ccl, or an end ccl
- X * character as a first character. Anything
- X * else gets set in the bitmap.
- X */
- X if (*++patptr == MC_NCCL)
- X {
- X patptr++;
- X mcptr->mc_type = NCCL;
- X }
- X else
- X mcptr->mc_type = CCL;
- X
- X if ((ochr = *patptr) == MC_ECCL)
- X {
- X mlwrite("%%No characters in character class");
- X return (FALSE);
- X }
- X else
- X {
- X if (ochr == MC_ESC)
- X ochr = *++patptr;
- X
- X setbit(ochr, bmap);
- X patptr++;
- X }
- X
- X while (ochr != '\0' && (pchr = *patptr) != MC_ECCL)
- X {
- X switch (pchr)
- X {
- X /* Range character loses its meaning
- X * if it is the last character in
- X * the class.
- X */
- X case MC_RCCL:
- X if (*(patptr + 1) == MC_ECCL)
- X setbit(pchr, bmap);
- X else
- X {
- X pchr = *++patptr;
- X while (++ochr <= pchr)
- X setbit(ochr, bmap);
- X }
- X break;
- X
- X /* Note: no break between case MC_ESC and the default.
- X */
- X case MC_ESC:
- X pchr = *++patptr;
- X default:
- X setbit(pchr, bmap);
- X break;
- X }
- X patptr++;
- X ochr = pchr;
- X }
- X
- X *ppatptr = patptr;
- X
- X if (ochr == '\0')
- X {
- X mlwrite("%%Character class not ended");
- X free(bmap);
- X return FALSE;
- X }
- X return TRUE;
- X}
- X
- X/*
- X * biteq -- is the character in the bitmap?
- X */
- Xstatic int biteq(bc, cclmap)
- Xint bc;
- XBITMAP cclmap;
- X{
- X if (bc >= HICHAR)
- X return FALSE;
- X
- X return( (*(cclmap + (bc >> 3)) & BIT(bc & 7))? TRUE: FALSE );
- X}
- X
- X/*
- X * clearbits -- Allocate and zero out a CCL bitmap.
- X */
- Xstatic BITMAP clearbits()
- X{
- X char *malloc();
- X
- X BITMAP cclstart, cclmap;
- X register int j;
- X
- X if ((cclmap = cclstart = (BITMAP) malloc(HIBYTE)) != NULL)
- X for (j = 0; j < HIBYTE; j++)
- X *cclmap++ = 0;
- X
- X return (cclstart);
- X}
- X
- X/*
- X * freebits -- Free up any CCL bitmaps.
- X */
- Xstatic freebits()
- X{
- X register MC *mcptr;
- X
- X mcptr = &mcpat[0];
- X
- X while (mcptr->mc_type != MCNIL)
- X {
- X if ((mcptr->mc_type & MASKCL) == CCL ||
- X (mcptr->mc_type & MASKCL) == NCCL)
- X free(mcptr->u.cclmap);
- X mcptr++;
- X }
- X}
- X
- X/*
- X * setbit -- Set a bit (ON only) in the bitmap.
- X */
- Xstatic setbit(bc, cclmap)
- Xint bc;
- XBITMAP cclmap;
- X{
- X if (bc < HICHAR)
- X *(cclmap + (bc >> 3)) |= BIT(bc & 7);
- X}
- X#endif
- END_OF_search.c
- if test 30773 -ne `wc -c <search.c`; then
- echo shar: \"search.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- echo shar: End of archive 12 \(of 14\).
- cp /dev/null ark12isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 14 archives.
- echo "See the readme file"
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-